package com.hex.ds.hdrs.period.task.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.bigdata.hbda.base.Page;
import com.hex.ds.hdrs.common.annotation.AppCodeVerification;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.page.PageData;
import com.hex.ds.hdrs.common.utils.BaseUtil;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.common.utils.MapUtil;
import com.hex.ds.hdrs.period.job.po.PeriodJob;
import com.hex.ds.hdrs.period.job.po.PeriodJobDef;
import com.hex.ds.hdrs.period.job.service.PeriodJobDefService;
import com.hex.ds.hdrs.period.task.converter.IPeriodTaskDefConverter;
import com.hex.ds.hdrs.period.task.dao.PeriodTaskDefDao;
import com.hex.ds.hdrs.period.task.dto.PeriodTaskDefDto;
import com.hex.ds.hdrs.period.task.dto.PeriodTaskDto;
import com.hex.ds.hdrs.period.task.dto.depend.*;
import com.hex.ds.hdrs.period.task.po.MutexPool;
import com.hex.ds.hdrs.period.task.po.PeriodTask;
import com.hex.ds.hdrs.period.task.po.PeriodTaskDef;
import com.hex.ds.hdrs.period.task.vo.TaskDependDetailVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 周期任务定义表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2020-11-26
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class PeriodTaskDefService {

    private final PeriodTaskDefDao periodTaskDefDao;

    private final PeriodTaskService periodTaskService;

    private final MutexPoolService mutexPoolService;

    private final IPeriodTaskDefConverter periodTaskDefConverter;

    private final PeriodJobDefService periodJobDefService;

    /**
     * 查询全量任务定义list
     *
     * @return
     */
    public List<PeriodTaskDef> qryTaskDefList() {
        log.info("查询【PeriodTaskDefService.qryTaskDefList方法】");
        return this.periodTaskDefDao.qryTaskDefList();
    }

    public PeriodTaskDef qryPeriodTaskDef(String taskCode) {
        Map paramMap = new HashMap(16);
        paramMap.put("taskCode", taskCode);
        return qryPeriodTaskDef(paramMap);
    }

    /*
     * @Method: queryById <br>
     * @Param: [pkId] <br>
     * @Return: com.hex.ds.hdrs.period.task.po.PeriodTaskDef <br>
     * @Description：根据主键查询周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 18:03 <br>
     * @Version： V2.0.2<br>
     */
    public PeriodTaskDef queryById(String pkId) {
        Map paramMap = new HashMap(16);
        paramMap.put("pkId", pkId);
        return qryPeriodTaskDef(paramMap);
    }

    public PeriodTaskDef qryPeriodTaskDef(Map map) {
        return this.periodTaskDefDao.qryPeriodTaskDef(map);
    }

    /**
     * @Method: generateJobTask
     * @Param: [periodJob]
     * @Return: void
     * @Description： 任务定义生成实例
     * @Author： jd.chen
     * @Date： 2021/6/17 17:19
     * @Version： V1.0
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void generateJobTask(PeriodJob periodJob) {
        List<PeriodTask> periodTaskList = buildPeriodTask(periodJob);
        if (CollUtil.isNotEmpty(periodTaskList)){
            //已存在的任务实例
            List<PeriodTask> existPeriodTaskList = qryTaskByJobCodeBizDate(periodJob);
            Map<String, PeriodTask> periodTaskMap = periodTaskList.stream().collect(Collectors.toMap(PeriodTask::getTaskCode, v -> v, (k1, k2) -> k1));
            List<String> sortTaskList = periodTaskService.sortByDependTask(periodTaskList);
            for (String taskCode : sortTaskList) {
                // 不存在则添加
                if (!checkPeriodTaskExist(taskCode,existPeriodTaskList)){
                    periodTaskService.add(periodTaskMap.get(taskCode));
                }
            }
        }
    }

    /**
     * @Method checkPeriodTaskExist <br>
     * @Param taskCode
     * @Param existPeriodTaskList <br>
     * @Return  <br>
     * @Description 任务实例是否存在<br>
     * @Author Qiao jian<br>
     * @Date 2024/8/2 15:44 <br>
     * @Version V1.0<br>
     */
    public boolean checkPeriodTaskExist(String taskCode,List<PeriodTask> existPeriodTaskList){
        return existPeriodTaskList.stream().anyMatch(task -> StrUtil.equalsIgnoreCase(taskCode,task.getTaskCode()));
    }

    /**
     * @Method qryTaskByJobCodeBizDate <br>
     * @Param periodJob <br>
     * @Return  <br>
     * @Description 根据作业编码 业务日志查询任务实例<br>
     * @Author Qiao jian<br>
     * @Date 2024/8/2 15:43 <br>
     * @Version V1.0<br>
     */
    public List<PeriodTask> qryTaskByJobCodeBizDate(PeriodJob periodJob){
        PeriodTaskDto periodTaskDto = new PeriodTaskDto();
        periodTaskDto.setJobCode(periodJob.getJobCode());
        periodTaskDto.setBizDate(periodJob.getBizDate());
        return periodTaskService.queryList(periodTaskDto);
    }

    /*
     * @Method: buildPeriodTask <br>
     * @Param: [periodJob] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.task.po.PeriodTask> <br>
     * @Description：构建要创建的任务实例计划<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/16 1:33 <br>
     * @Version： V2.0.2<br>
     */
    private List<PeriodTask> buildPeriodTask(PeriodJob periodJob) {
        List<PeriodTask> periodTaskList = new ArrayList<>();
        List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(periodJob.getJobCode());
        log.debug("根据作业实例查询任务实例集合,获取到的任务实例集合大小:{}", (null == periodTaskDefList ? 0 : periodTaskDefList.size()));
        if (CollectionUtil.isEmpty(periodTaskDefList)) {
            log.error("周期作业定义: 【{}】下没有配置周期任务定义", periodJob.getJobCode());
        } else {
            for (PeriodTaskDef periodTaskDef : periodTaskDefList) {
                PeriodTask periodTask = clone(periodTaskDef, periodJob);
                periodTaskList.add(periodTask);
            }
        }
        return periodTaskList;
    }

    public PeriodTask clone(PeriodTaskDef def, PeriodJob periodJob) {
        PeriodTask periodTask = new PeriodTask();
        periodTask.setPkId(BaseUtil.getPkId());
        periodTask.setJobCode(def.getJobCode());
        periodTask.setTaskCode(def.getTaskCode());
        periodTask.setTaskName(def.getTaskName());
        periodTask.setBizDate(periodJob.getBizDate());
        periodTask.setShellPath(def.getShellPath());
        periodTask.setDependJob(def.getDependJob());
        periodTask.setDependTask(def.getDependTask());
        periodTask.setTaskStatus(Const.TASK_TODO_RUN);
        periodTask.setErrCount(0);
        periodTask.setCrtTs(HdrsDateUtil.getCurrentTime());
        periodTask.setUpTs(HdrsDateUtil.getCurrentTime());
        periodTask.setJobPkId(periodJob.getPkId());
        periodTask.setIsEndTask(def.getIsEndTask());
        periodTask.setMutexJob(def.getMutexJob());
        periodTask.setMutexTask(def.getMutexTask());
        periodTask.setIsOrder(def.getIsOrder());
        // periodTask.setBatchTag(periodJob.);
        periodTask.setAllowErrCount(def.getAllowErrCount());
        periodTask.setResNum(def.getResNum());
        periodTask.setPriorityLevel(def.getPriorityLevel());
        periodTask.setAppCode(def.getAppCode());
        // periodTask.setAgentCode("");
        periodTask.setAppointAgentCode(def.getAppointAgentCode());
        periodTask.setPlanExecDuration(def.getPlanExecDuration());
        periodTask.setOverPlanDuration(def.getOverPlanDuration());
        periodTask.setErrDifferDuration(def.getErrDifferDuration());
        periodTask.setExtParam(def.getExtParam());
        // periodTask.setIsOneAgent("");
        // periodTask.setExecStTs("");
        // periodTask.setExecStEnd("");
        // periodTask.setTaskExecLog("");
        return periodTask;
    }

    public List<PeriodTaskDef> getTaskDefsByJobCode(String jobCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("jobCode", jobCode);
        return periodTaskDefDao.qryTaskDefList(map);
    }

    /**
     * 通过应用编码查询任务信息
     *
     * @param appCode
     * @return
     */
    public List<PeriodTaskDef> qryTaskDefByAppCode(String appCode) {
        Map<String, Object> map = new HashMap<>();
        if (StrUtil.isNotBlank(appCode)) {
            map.put("appCode", appCode);
        }
        return this.periodTaskDefDao.qryTaskDefList(map);
    }

    /**
     * 判断任务编码是否重复
     *
     * @param paramMap
     * @return
     */
    public Boolean validateTaskCode(Map paramMap) {
        log.info("任务编码判断是否重复【PeriodTaskDefService.validateTaskCode】参数paramMap: {}", paramMap);
        Map params = new HashMap();
        params.put("taskCode", paramMap.get("taskCode"));
        if (paramMap.containsKey("taskCode") && paramMap.get("taskCode") != null) {
            PeriodTaskDef periodTaskDef = this.periodTaskDefDao.qryPeriodTaskDef(params);
            if (null != periodTaskDef && !periodTaskDef.getPkId().equals(paramMap.get("pkId"))) {
                return false;
            }
        }
        return true;
    }

    /*
     * @Method: add <br>
     * @Param: [periodTaskDefDto] <br>
     * @Return: com.hex.ds.hdrs.period.task.po.PeriodTaskDef <br>
     * @Description：新增周期任务定义（更新内存）<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 16:02 <br>
     * @Version： V2.0.2<br>
     */
    public PeriodTaskDef add(PeriodTaskDefDto periodTaskDefDto) {
        PeriodTaskDef periodTaskDef = periodTaskDefConverter.toPeriodTaskDefForAdd(periodTaskDefDto);
        add(periodTaskDef);
        return periodTaskDef;
    }

    /*
     * @Method: checkCirculateDepend <br>
     * @Param: [crudTaskCode, crudJobCode, dependJob, dependTask] <br>
     * @Return: void <br>
     * @Description：循环依检查<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/6 20:21 <br>
     * @Version： V2.0.2<br>
     */
    public void checkCirculateDepend(String crudTaskCode, String crudJobCode, String dependJob, String dependTask) {
        checkTaskCirculateDepend(crudTaskCode, crudJobCode, dependTask);
        checkJobCirculateDepend(crudTaskCode, crudJobCode, dependJob);
    }

    /*
     * @Method: checkTaskCirculateDepend <br>
     * @Param: [crudTaskCode, crudJobCode, dependTask] <br>
     * @Return: void <br>
     * @Description：上游任务循环依赖检查<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/6 20:21 <br>
     * @Version： V2.0.2<br>
     */
    private void checkTaskCirculateDepend(String crudTaskCode, String crudJobCode, String dependTask) {
        if (StrUtil.isBlank(dependTask)) {
            return;
        }
        List<String> dependTaskList = Arrays.asList(StrUtil.split(dependTask, ","));
        for (String dependTaskCode : dependTaskList) {
            if (crudTaskCode.equals(dependTaskCode)) {
                throw new RuntimeException("该任务的【上游依赖任务】存在循环依赖请检查！");
            }
            PeriodTaskDef periodTaskDef = qryPeriodTaskDef(dependTaskCode);
            if (periodTaskDef != null) {
                checkCirculateDepend(crudTaskCode, crudJobCode, periodTaskDef.getDependJob(), periodTaskDef.getDependTask());
            }
        }
    }

    /*
     * @Method: checkJobCirculateDepend <br>
     * @Param: [crudTaskCode, crudJobCode, dependJob] <br>
     * @Return: void <br>
     * @Description：上游作业循环依赖检查<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/6 20:22 <br>
     * @Version： V2.0.2<br>
     */
    private void checkJobCirculateDepend(String crudTaskCode, String crudJobCode, String dependJob) {
        if (StrUtil.isBlank(dependJob)) {
            return;
        }
        List<String> dependJobList = Arrays.asList(StrUtil.split(dependJob, ","));
        for (String dependJobCode : dependJobList) {
            if (crudJobCode.equals(dependJobCode)) {
                throw new RuntimeException("该任务的【上游依赖作业】存在循环依赖请检查！");
            }
            List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(dependJobCode);
            for (PeriodTaskDef periodTaskDef : periodTaskDefList) {
                checkCirculateDepend(crudTaskCode, crudJobCode, periodTaskDef.getDependJob(), periodTaskDef.getDependTask());
            }
        }
    }

    /*
     * @Method: add <br>
     * @Param: [periodTaskDef] <br>
     * @Return: void <br>
     * @Description：新增周期任务定义（不更新内存）<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 13:54 <br>
     * @Version： V2.0.2<br>
     */
    public void add(PeriodTaskDef periodTaskDef) {
//        checkCirculateDepend(periodTaskDef.getTaskCode(), periodTaskDef.getJobCode(), periodTaskDef.getDependJob(), periodTaskDef.getDependTask());
        log.info("新增周期任务定义,任务编码:{}",periodTaskDef.getTaskCode());
        int count = periodTaskDefDao.insert(periodTaskDef);
        if (count != 1) {
            throw new RuntimeException("新增周期任务定义失败！");
        }
    }

    /*
     * @Method: modifyById <br>
     * @Param: [periodTaskDefDto] <br>
     * @Return: void <br>
     * @Description：更新周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 18:27 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyById(PeriodTaskDefDto periodTaskDefDto) {
        PeriodTaskDef periodTaskDef = periodTaskDefConverter.toPeriodTaskDefForModify(periodTaskDefDto);
        modifyById(periodTaskDef);
    }

    /*
     * @Method: modifyById <br>
     * @Param: [periodTaskDef] <br>
     * @Return: void <br>
     * @Description：更新周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 18:27 <br>
     * @Version： V2.0.2<br>
     */
    public void modifyById(PeriodTaskDef periodTaskDef) {
//        checkCirculateDepend(periodTaskDef.getTaskCode(), periodTaskDef.getJobCode(), periodTaskDef.getDependJob(), periodTaskDef.getDependTask());
        log.info("更新周期任务定义,任务编码:{}",periodTaskDef.getTaskCode());
        int count = periodTaskDefDao.update(periodTaskDef);
        if (count != 1) {
            throw new RuntimeException("周期任务定义更新失败");
        }
    }

    /*
     * @Method: modifyByCode <br>
     * @Param: [periodTaskDef] <br>
     * @Return: void <br>
     * @Description：根据任务编码更新<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/6 20:33 <br>
     * @Version： V2.0.2<br>
     */
    public void modifyByCode(PeriodTaskDef periodTaskDef) {
        PeriodTaskDef bdPeriodTaskDef = qryPeriodTaskDef(periodTaskDef.getTaskCode());
        periodTaskDef.setPkId(bdPeriodTaskDef.getPkId());
        modifyById(periodTaskDef);
    }

    /**
     * 批量删除
     *
     * @param list
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean doDeleteByPkId(List<PeriodTaskDef> list) {
        log.info("批量删除【PeriodTaskDefService.doDeleteByPkId】参数list: {}", list.toArray());
        if (CollectionUtils.isNotEmpty(list)) {
            for (PeriodTaskDef periodTaskDef : list) {
                removeById(periodTaskDef.getPkId());
            }
        }
        return true;
    }

    /*
     * @Method: removeById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据主键删除周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 14:14 <br>
     * @Version： V2.0.2<br>
     */
    public void removeById(String pkId) {
        int count = periodTaskDefDao.removeById(pkId);
        if (count != 1) {
            throw new RuntimeException("周期任务定义删除失败");
        }
    }

    /*
     * @Method: removeByJobCode <br>
     * @Param: [jobCode] <br>
     * @Return: void <br>
     * @Description：根据作业编码更新周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 14:14 <br>
     * @Version： V2.0.2<br>
     */
    public void removeByJobCode(String jobCode) {
        periodTaskDefDao.removeByJobCode(jobCode);
    }

    /*
     * @Method: removeByTaskCode <br>
     * @Param: [taskCode] <br>
     * @Return: void <br>
     * @Description：根据任务编码更新周期任务定义<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 14:17 <br>
     * @Version： V2.0.2<br>
     */
    public void removeByTaskCode(String taskCode) {
        log.info("根据任务编码更新周期任务定义,任务编码：{}",taskCode);
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        removeById(periodTaskDef.getPkId());
    }

    /**
     * 获取当前应用下所有任务定义
     *
     * @return
     */
    @AppCodeVerification(paramObject = TaskDependDetailVO.class)
    public List<PeriodTaskDef> getTaskList(TaskDependDetailVO taskDependDetail, Page page) {
        Map map = new HashMap();
        if (StringUtils.isNotBlank(taskDependDetail.getTaskNameAndTaskCode())
                && !"undefined".equals(taskDependDetail.getTaskNameAndTaskCode())) {
            map.put("taskNameAndTaskCode", taskDependDetail.getTaskNameAndTaskCode());
        }
        if (StringUtils.isNotBlank(taskDependDetail.getTaskCode())
                && !"undefined".equals(taskDependDetail.getTaskCode())) {
            map.put("taskCode", taskDependDetail.getTaskCode());
        }
        if (StringUtils.isNotBlank(taskDependDetail.getTaskName())
                && !"undefined".equals(taskDependDetail.getTaskName())) {
            map.put("taskName", taskDependDetail.getTaskName());
        }
        map.put("appCode", taskDependDetail.getAppCode());
        List<PeriodTaskDef> taskList = null;
        // 1为当前应用 2为其他应用
        if (StringUtils.isBlank(taskDependDetail.getAppName()) || "1".equals(taskDependDetail.getAppName())) {
            taskList = this.periodTaskDefDao.qryTaskDef(map, page);
        } else if ("2".equals(taskDependDetail.getAppName())) {
            taskList = this.periodTaskDefDao.qryTaskDefNotCurrApp(map, page);
        }
        return taskList;
    }

    /**
     * 获取当前应用下所有任务定义
     *
     * @return
     */
    @AppCodeVerification(paramObject = String.class)
    public List<PeriodTaskDef> getTaskListByCurrentApp(String appCode) {
        return this.qryTaskDefByAppCode(appCode);
    }

    /**
     * 获取当前应用所有依赖任务
     *
     * @return
     */
    @AppCodeVerification(paramObject = LinkedHashMap.class)
    public PageData getDependTaskByCurrentApp(Map map) {
        String taskNameOrCode = (String) map.get("taskNameOrCode");
        if (StringUtils.isBlank(taskNameOrCode) || "undefined".equals(taskNameOrCode)) {
            map.remove("taskNameOrCode");
        }
        Page page = new Page();
        Integer pageSize = (Integer) map.get("pageSize");
        Integer pageIndex = (Integer) map.get("pageIndex");
        page.setPageSize(pageSize);
        page.setPageIndex(pageIndex);
        PageData data = new PageData(this.periodTaskDefDao.qryTaskDefDependList(map, page), page);
        return data;
    }

    /**
     * @Method: batchUpdatePriorityLevel
     * @Param: [periodTaskDefDto]
     * @Return: void
     * @Description: 批量更新任务优先级
     * @Author: ji.tang
     * @Date: 2022/11/22 14:11
     * @Version: V1.0
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdatePriorityLevel(PeriodTaskDefDto periodTaskDefDto) {
        if (CollectionUtil.isNotEmpty(periodTaskDefDto.getPkIds())) {
            for (String pkId : periodTaskDefDto.getSelectionList()) {
                PeriodTaskDef periodTaskDef = queryById(pkId);
                periodTaskDef.setPriorityLevel(periodTaskDefDto.getPriorityLevel());
                modifyById(periodTaskDef);
            }
        }
    }

    /*
     * @Method: batchUpdateTaskLevel <br>
     * @Param: [jobCode, level] <br>
     * @Return: void <br>
     * @Description：根据作业编码批量更新周期任务的有限级<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/22 18:29 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateTaskLevel(String jobCode, Integer level) {
        StringBuilder sb = new StringBuilder();
        List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(jobCode);
        for (PeriodTaskDef periodTaskDef : periodTaskDefList) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append(periodTaskDef.getTaskCode());
            periodTaskDef.setPriorityLevel(level);
            modifyById(periodTaskDef);
        }
        log.info("根据作业编码批量更新周期任务的有限级,任务编码：{}",sb);
    }

    /**
     * @Method: batchUpdateTaskInf
     * @Param: [periodTaskDefDto]
     * @Return: void
     * @Description: 批量修改任务信息 分类型是英文其他值有默认值
     * @Author: ji.tang
     * @Date: 2022/11/22 14:12
     * @Version: V1.0
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateTaskInf(PeriodTaskDefDto periodTaskDefDto) {
        if (CollectionUtils.isNotEmpty(periodTaskDefDto.getPkIds())) {
            for (String pkId : periodTaskDefDto.getPkIds()) {
                PeriodTaskDef periodTaskDef = queryById(pkId);
                if ("isOrder".equals(periodTaskDefDto.getType())) {
                    periodTaskDef.setIsOrder(periodTaskDefDto.getIsOrder());
                }
                if ("resNum".equals(periodTaskDefDto.getType())) {
                    periodTaskDef.setResNum(periodTaskDefDto.getResNum());
                }
                if ("priorityLevel".equals(periodTaskDefDto.getType())) {
                    periodTaskDef.setPriorityLevel(periodTaskDefDto.getPriorityLevel());
                }
                if ("allowErrCount".equals(periodTaskDefDto.getType())) {
                    periodTaskDef.setAllowErrCount(periodTaskDefDto.getAllowErrCount());
                }
                if ("errDifferDuration".equals(periodTaskDefDto.getType())) {
                    periodTaskDef.setErrDifferDuration(periodTaskDefDto.getErrDifferDuration());
                }
                modifyById(periodTaskDef);
            }
        }
    }

    /**
     * @Method: batchUpdateTaskByJobCode
     * @Param: [periodTaskDefDto]
     * @Return: void
     * @Description: 批量更新任务配置
     * @Author: ji.tang
     * @Date: 2022/11/22 14:13
     * @Version: V1.0
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchUpdateTaskByJobCode(PeriodTaskDefDto periodTaskDefDto) {
        if (CollectionUtils.isNotEmpty(periodTaskDefDto.getSelectionList())) {
            for (String jobCode : periodTaskDefDto.getSelectionList()) {
                List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(jobCode);
                for (PeriodTaskDef periodTaskDef : periodTaskDefList) {
                    if (StringUtils.isNotBlank(periodTaskDefDto.getIsOrder())) {
                        periodTaskDef.setIsOrder(periodTaskDefDto.getIsOrder());
                    }
                    if (StringUtils.isNotBlank(String.valueOf(periodTaskDefDto.getAllowErrCount()))) {
                        periodTaskDef.setAllowErrCount(periodTaskDefDto.getAllowErrCount());
                    }
                    if (StringUtils.isNotBlank(periodTaskDefDto.getErrDifferDuration())) {
                        periodTaskDef.setErrDifferDuration(periodTaskDefDto.getErrDifferDuration());
                    }
                    modifyById(periodTaskDef);
                }
            }
        }
    }

    /**
     * 查询任务定义数量
     *
     * @return
     */
    public int qryTaskDefCount() {
        return this.periodTaskDefDao.qryTaskDefCount();
    }

    public List<PeriodTaskDef> selectPage(PeriodTaskDefDto periodTaskDefDto, Page page) {
        log.debug("【PeriodTaskDefService.selectPage】periodTaskDefDto: {}", periodTaskDefDto);
        Map map = MapUtil.Entity2Map(periodTaskDefDto);
        if (StringUtils.isBlank(periodTaskDefDto.getAppCode()) && CollectionUtils.isEmpty(periodTaskDefDto.getAppCodeList())) {
            return new ArrayList<>();
        }
        return this.periodTaskDefDao.qryTaskPage(map, page);
    }

    public List<PeriodTaskDef> findMutexTaskList(PeriodTaskDefDto periodTaskDefDto, Page page) {
        log.debug("【PeriodTaskDefService.selectPage】periodTaskDefDto: {}", periodTaskDefDto);
        Map map = MapUtil.Entity2Map(periodTaskDefDto);
        if (StringUtils.isNotBlank(periodTaskDefDto.getAppCode())) {
            return this.getAppTaskList(map, page);
        } else {
            return this.getAdminTaskList(periodTaskDefDto, map, page);
        }
    }

    private List<PeriodTaskDef> getAdminTaskList(PeriodTaskDefDto periodTaskDefDto, Map map, Page page) {
        if (StringUtils.isBlank(periodTaskDefDto.getGroupCode())) {
            return new ArrayList<>();
        }
        List<MutexPool> mutexPoolList = this.mutexPoolService.qryMutexPoolList(periodTaskDefDto.getGroupCode());
        List<String> taskCodeList = new ArrayList<>();
        for (MutexPool mutexPool : mutexPoolList) {
            if (StringUtils.isNotBlank(mutexPool.getTaskCodes())) {
                String[] taskCodes = mutexPool.getTaskCodes().split(",");
                taskCodeList.addAll(Arrays.asList(taskCodes));
            }
        }
        if (CollectionUtils.isEmpty(taskCodeList)) {
            return new ArrayList<>();
        }
        map.put("taskCodeList", taskCodeList);
        return this.periodTaskDefDao.qryTaskPage(map, page);
    }

    private List<PeriodTaskDef> getAppTaskList(Map map, Page page) {
        MutexPool mutexPool = this.mutexPoolService.qryMutexPool((String) map.get("appCode"), Const.MUTEX_POOL_TYPE_APP);
        if (mutexPool == null) {
            return new ArrayList<>();
        }
        String[] taskCodes = mutexPool.getTaskCodes().split(",");
        if (taskCodes == null || taskCodes.length < 1) {
            return new ArrayList<>();
        }
        map.put("taskCodeList", Arrays.asList(taskCodes));
        return this.periodTaskDefDao.qryTaskPage(map, page);
    }

    /*
     * @Method: upDependChat <br>
     * @Param: [taskCode] <br>
     * @Return: com.hex.ds.hdrs.period.task.dto.depend.TaskAllDependDto <br>
     * @Description：获取指定任务上游依赖图<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:33 <br>
     * @Version： V2.0.2<br>
     */
    public TaskAllDependDto upDependChat(String taskCode, String showType) {
        log.info("获取指定任务上游依赖图，任务编码：{}",taskCode);
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        TaskAllDependDto taskAllDependDto = new TaskAllDependDto(periodTaskDef.getTaskName());
        buildUpDependChatData(showType, periodTaskDef, periodTaskDef, taskAllDependDto);
        return taskAllDependDto;
    }

    public TaskDependDto upDepend(String taskCode) {
        //任务编码
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        TaskDependDto taskDependDto = new TaskDependDto(periodTaskDef.getPkId(),periodTaskDef.getTaskCode());
        buildUpDependData(periodTaskDef,taskDependDto);
        return taskDependDto;
    }

    public TaskDependDto taskDef(String taskCode) {
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        TaskDependDto taskDependDto = new TaskDependDto(periodTaskDef.getPkId(),periodTaskDef.getTaskCode());
        return taskDependDto;
    }

    public TaskDependDto downDepend(String taskCode) {
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        TaskDependDto taskDependDto = new TaskDependDto(periodTaskDef.getPkId(),periodTaskDef.getTaskCode());
        buildDownDependData(periodTaskDef, taskDependDto);
        return taskDependDto;
    }

    private void buildDownDependData(PeriodTaskDef periodTaskDef, TaskDependDto taskDependDto) {
        DependNodesDataDto dependNodesDataDto = new DependNodesDataDto();
        //获取该节点的下游依赖
        List<PeriodTaskDef> periodTaskDefList = queryListByDependTask(periodTaskDef.getTaskCode());
        ArrayList<Object> nextDep = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(periodTaskDefList)){
            for (PeriodTaskDef taskDef : periodTaskDefList) {
                //1.将每一个下游依赖设置到nextDep里
                nextDep.add(new TaskDependDto(taskDef.getPkId(),taskDef.getTaskCode()));
                //2.设置每一条边的信息
                nextDep.add(new EdgeDataDto(taskDef.getPkId(),periodTaskDef.getPkId()));
            }
        }
        List<PeriodTaskDef> crunJobTaskList = getTaskDefsByJobCode(periodTaskDef.getJobCode());
        List<String> sortTaskCodes = sortByDependTask(crunJobTaskList);
        if (sortTaskCodes.indexOf(periodTaskDef.getTaskCode()) == (crunJobTaskList.size() - 1)) {
            List<PeriodTaskDef> downDependList = queryListByDependJob(periodTaskDef.getJobCode());
            for (PeriodTaskDef dependTaskDef : downDependList) {
                //1.将每一个下游依赖设置到nextDep里
                nextDep.add(new TaskDependDto(dependTaskDef.getPkId(),dependTaskDef.getTaskCode()));
                //2.设置每一条边的信息
                nextDep.add(new EdgeDataDto(dependTaskDef.getPkId(),periodTaskDef.getPkId()));
            }
        }
        if (nextDep.size() == 0){
            throw new RuntimeException("该任务不存在下游依赖");
        }
        dependNodesDataDto.setNextDep(nextDep);
        taskDependDto.setData(dependNodesDataDto);
    }

    private void buildUpDependData(PeriodTaskDef periodTaskDef, TaskDependDto taskDependDto) {
        if (CollectionUtil.isEmpty(periodTaskDef.getDependTaskList()) && CollectionUtil.isEmpty(periodTaskDef.getDependJobList())){
            throw new RuntimeException("该任务不存在上游依赖");
        }
        DependNodesDataDto dependNodesDataDto = new DependNodesDataDto();
        List<Object> lastDep = new ArrayList<>();
        //判断是否有上游节点
        if(!CollectionUtil.isEmpty(periodTaskDef.getDependTaskList())){
            for (String taskCode : periodTaskDef.getDependTaskList()) {
                PeriodTaskDef dependTaskDef = qryPeriodTaskDef(taskCode);
                if (dependTaskDef == null) {
                    throw new RuntimeException("上游任务定义【" + taskCode + "】不存在");
                }
                //添加任务子节点信息
                lastDep.add(new TaskDependDto(dependTaskDef.getPkId(),dependTaskDef.getTaskCode()));
                //添加任务节点间的边信息
                lastDep.add(new EdgeDataDto(periodTaskDef.getPkId(), dependTaskDef.getPkId()));
            }
        }
        if(!CollectionUtil.isEmpty(periodTaskDef.getDependJobList())){
            for (String jobCode : periodTaskDef.getDependJobList()) {
                PeriodJobDef jobDefByJobCode = periodJobDefService.getJobDefByJobCode(jobCode);
                DependNodesDataDto dependNodesDataDto1 = new DependNodesDataDto();
                List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(jobCode);
                if (CollectionUtil.isEmpty(periodTaskDefList)) {
                    throw new RuntimeException("上游依赖作业定义【" + jobCode + "】不存在或其下没有任务定义！");
                }
                //添加作业子节点
                TaskDependDto taskDependDto1 = new TaskDependDto(jobDefByJobCode.getPkId(),jobCode);
                taskDependDto1.setShape("job");
                ArrayList<TaskDependDto> children = new ArrayList<>();
                for (PeriodTaskDef taskDef : periodTaskDefList) {
                    TaskDependDto taskDependDtoChildren = new TaskDependDto(taskDef.getPkId(),taskDef.getTaskCode());
                    taskDependDtoChildren.setJobCode(jobCode);
                    children.add(taskDependDtoChildren);
                }
                dependNodesDataDto1.setChildren(children);
                taskDependDto1.setData(dependNodesDataDto1);
                lastDep.add(taskDependDto1);
                lastDep.add(new EdgeDataDto(periodTaskDef.getPkId(),jobDefByJobCode.getPkId()));
            }
        }
        dependNodesDataDto.setLastDep(lastDep);
        taskDependDto.setData(dependNodesDataDto);
    }

    public String qryTaskStatus(String taskCode,String bizDate) {
        Map map = new HashMap(16);
        map.put("taskCode", taskCode);
        map.put("bizDate", bizDate);
        List<PeriodTask> taskList = periodTaskService.qryPeriodTaskList(map);
        if (taskList.size() == 1) {
            return taskList.get(0).getTaskStatus();
        } else {
            return "null";
        }
    }
    /*
     * @Method: buildUpDependChatData <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建指定任务上游依赖图数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:33 <br>
     * @Version： V2.0.2<br>
     */
    private void buildUpDependChatData(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        if ("ALL_DEPEND".equals(showType) || isShowDepend(rootPeriodTaskDef, periodTaskDef)) {
            log.info("构建指定任务上游依赖图数据,任务编码：{}",periodTaskDef.getTaskCode());
            buildTaskNode(periodTaskDef, taskAllDependDto);
            buildDependJobLike(showType, rootPeriodTaskDef, periodTaskDef, taskAllDependDto);
            buildDependTaskLike(showType, rootPeriodTaskDef, periodTaskDef, taskAllDependDto);
        }
    }

    private boolean isShowDepend(PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef) {
        return rootPeriodTaskDef.getPkId().equals(periodTaskDef.getPkId())
                || rootPeriodTaskDef.getDependJobList().contains(periodTaskDef.getJobCode())
                || rootPeriodTaskDef.getDependTaskList().contains(periodTaskDef.getTaskCode());
    }

    /*
     * @Method: buildTaskNode <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：够建当前任务节点信息<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:33 <br>
     * @Version： V2.0.2<br>
     */
    private void buildTaskNode(PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        DependNodesDto crunTaskNode = new DependNodesDto(periodTaskDef.getTaskCodeAndName(), periodTaskDef.getTaskCodeAndName(), false);
        if (!taskAllDependDto.getNodes().contains(crunTaskNode)) {
            log.info("够建当前任务节点信息,任务编码:{}",periodTaskDef.getTaskCode());
            taskAllDependDto.getNodes().add(crunTaskNode);
        }
    }

    /*
     * @Method: buildDependJobLike <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建上游依赖作业节点数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:34 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDependJobLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        StringBuilder sb = new StringBuilder();
        if (CollectionUtil.isNotEmpty(periodTaskDef.getDependJobList())) {
            for (String jobCode : periodTaskDef.getDependJobList()) {
                List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(jobCode);
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(jobCode);
                if (CollectionUtil.isEmpty(periodTaskDefList)) {
                    throw new RuntimeException("上游依赖作业定义【" + jobCode + "】不存在或其下没有任务定义！");
                }
                List<String> sortPeriodTaskDefList = sortByDependTask(periodTaskDefList);
                PeriodTaskDef dependTaskDef = periodTaskDefList.stream()
                        .filter(o -> o.getTaskCode().equals(sortPeriodTaskDefList.get(sortPeriodTaskDefList.size() - 1))).collect(Collectors.toList()).get(0);
                buildNodeLike(showType, rootPeriodTaskDef, periodTaskDef, dependTaskDef, taskAllDependDto);
            }
            log.info("构建上游依赖作业节点数据,作业编码:{}",sb);
        }
    }

    /*
     * @Method: buildDependTaskLike <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建上游依赖任务节点数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:34 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDependTaskLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        StringBuilder sb = new StringBuilder();
        if (CollectionUtil.isNotEmpty(periodTaskDef.getDependTaskList())) {
            for (String taskCode : periodTaskDef.getDependTaskList()) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(taskCode);
                PeriodTaskDef dependTaskDef = qryPeriodTaskDef(taskCode);
                if (dependTaskDef == null) {
                    throw new RuntimeException("上游任务定义【" + taskCode + "】不存在");
                }
                buildNodeLike(showType, rootPeriodTaskDef, periodTaskDef, dependTaskDef, taskAllDependDto);
            }
            log.info("构建上游依赖任务节点数据,任务编码:{}",sb);
        }
    }

    /*
     * @Method: buildNodeLike <br>
     * @Param: [fromTaskDef, toTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建上游依赖节点与节点关系线数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 11:34 <br>
     * @Version： V2.0.2<br>
     */
    private void buildNodeLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, PeriodTaskDef dependTaskDef, TaskAllDependDto taskAllDependDto) {
        DependRelationDto dependRelationDto = new DependRelationDto(dependTaskDef.getTaskCodeAndName(), periodTaskDef.getTaskCodeAndName());
        if (!taskAllDependDto.getLinks().contains(dependRelationDto)) {
            log.info("构建上游依赖节点与节点关系线数据,rootPeriodTaskDef:{},periodTaskDef:{},dependTaskDef{}",rootPeriodTaskDef.getTaskCode(),periodTaskDef.getTaskCode(),dependTaskDef.getTaskCode());
            taskAllDependDto.getLinks().add(dependRelationDto);
        }
        buildUpDependChatData(showType, rootPeriodTaskDef, dependTaskDef, taskAllDependDto);
    }

    /*
     * @Method: upDependList <br>
     * @Param: [taskCode] <br>
     * @Return: com.hex.ds.hdrs.period.task.dto.depend.TaskAllDependListDto <br>
     * @Description：获取指定任务上游依赖列表<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 13:55 <br>
     * @Version： V2.0.2<br>
     */
    public TaskAllDependListDto upDependList(String taskCode) {
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        Set<PeriodTaskDef> dependTaskDefSet = buildDependTaskDefList(periodTaskDef);
        dependTaskDefSet.remove(periodTaskDef);
        return new TaskAllDependListDto().setPeriodTaskDefList(new ArrayList<>(dependTaskDefSet));
    }

    /*
     * @Method: buildDependTaskDefList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：获取指定任务上游依赖列表<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 13:55 <br>
     * @Version： V2.0.2<br>
     */
    public Set<PeriodTaskDef> buildDependTaskDefList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> dependTaskDefSet = new HashSet<>();
        dependTaskDefSet.add(periodTaskDef);
        dependTaskDefSet.addAll(buildDependJobList(periodTaskDef));
        dependTaskDefSet.addAll(buildDependTaskList(periodTaskDef));
        return dependTaskDefSet;
    }

    /*
     * @Method: buildDependJobList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：获取指定任务上游作业依赖<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 13:55 <br>
     * @Version： V2.0.2<br>
     */
    private Set<PeriodTaskDef> buildDependJobList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> dependTaskDefSet = new HashSet<>();
        if (CollectionUtil.isNotEmpty(periodTaskDef.getDependJobList())) {
            for (String jobCode : periodTaskDef.getDependJobList()) {
                List<PeriodTaskDef> periodTaskDefList = getTaskDefsByJobCode(jobCode);
                if (CollectionUtil.isEmpty(periodTaskDefList)) {
                    throw new RuntimeException("上游依赖作业定义【" + jobCode + "】不存在或没有任务定义");
                }
                List<String> sortPeriodTaskDefList = sortByDependTask(periodTaskDefList);
                PeriodTaskDef dependTaskDef = periodTaskDefList.stream()
                        .filter(o -> o.getTaskCode().equals(sortPeriodTaskDefList.get(sortPeriodTaskDefList.size() - 1))).collect(Collectors.toList()).get(0);
                dependTaskDefSet.addAll(buildDependTaskDefList(dependTaskDef));
            }
        }
        return dependTaskDefSet;
    }

    /*
     * @Method: buildDependTaskList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：获取指定任务上游游任务依赖<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 13:56 <br>
     * @Version： V2.0.2<br>
     */
    private Set<PeriodTaskDef> buildDependTaskList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> dependTaskDefSet = new HashSet<>();
        if (CollectionUtil.isNotEmpty(periodTaskDef.getDependTaskList())) {
            for (String taskCode : periodTaskDef.getDependTaskList()) {
                PeriodTaskDef dependTaskDef = qryPeriodTaskDef(taskCode);
                if (dependTaskDef == null) {
                    throw new RuntimeException("上游依赖任务定义【" + taskCode + "】不存在");
                }
                dependTaskDefSet.addAll(buildDependTaskDefList(dependTaskDef));
            }
        }
        return dependTaskDefSet;
    }

    /*
     * @Method: downDependChat <br>
     * @Param: [taskCode] <br>
     * @Return: com.hex.ds.hdrs.period.task.dto.depend.TaskAllDependDto <br>
     * @Description：获取指定任务的下游依赖图<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/25 16:34 <br>
     * @Version： V2.0.2<br>
     */
    public TaskAllDependDto downDependChat(String taskCode, String showType) {
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        TaskAllDependDto taskAllDependDto = new TaskAllDependDto(periodTaskDef.getTaskName());
        buildDownDependChatData(showType, periodTaskDef, periodTaskDef, taskAllDependDto);
        return taskAllDependDto;
    }

    /*
     * @Method: buildDownDependChatData <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建指定任务的下游依赖图数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/25 16:34 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDownDependChatData(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        if ("ALL_DEPEND".equals(showType) || isShowDownDepend(rootPeriodTaskDef, periodTaskDef)) {
            buildTaskNode(periodTaskDef, taskAllDependDto);
            log.info("构建指定任务的下游依赖图数据,rootPeriodTaskDef:{},periodTaskDef:{}",rootPeriodTaskDef.getTaskCode(),periodTaskDef.getTaskCode());
            buildDownDependJobLike(showType, rootPeriodTaskDef, periodTaskDef, taskAllDependDto);
            buildDownDependTaskLike(showType, rootPeriodTaskDef, periodTaskDef, taskAllDependDto);
        }
    }

    private boolean isShowDownDepend(PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef) {
        return rootPeriodTaskDef.getPkId().equals(periodTaskDef.getPkId())
                || periodTaskDef.getDependTaskList().contains(rootPeriodTaskDef.getTaskCode())
                || periodTaskDef.getDependJobList().contains(rootPeriodTaskDef.getJobCode());
    }

    /*
     * @Method: buildDownDependJobLike <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建指定任务下游依赖作业数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/25 16:34 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDownDependJobLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        List<PeriodTaskDef> crunJobTaskList = getTaskDefsByJobCode(periodTaskDef.getJobCode());
        List<String> sortTaskCodes = sortByDependTask(crunJobTaskList);
        StringBuilder sb = new StringBuilder();
        if (sortTaskCodes.indexOf(periodTaskDef.getTaskCode()) == (crunJobTaskList.size() - 1)) {
            List<PeriodTaskDef> periodTaskDefList = queryListByDependJob(periodTaskDef.getJobCode());
            if (CollectionUtil.isNotEmpty(periodTaskDefList)) {
                for (PeriodTaskDef downDependPeriodTaskDef : periodTaskDefList) {
                    if (sb.length() > 0) {
                        sb.append(", ");
                    }
                    sb.append(downDependPeriodTaskDef.getJobCode());
                    buildDownNodeLike(showType, rootPeriodTaskDef, periodTaskDef, downDependPeriodTaskDef, taskAllDependDto);
                }
                log.info("构建指定任务下游依赖作业数据,downDependPeriodTaskDef:{},rootPeriodTaskDef:{},periodTaskDef:{}",sb,rootPeriodTaskDef.getTaskCode(),periodTaskDef.getTaskCode());
            }
        }
    }

    /*
     * @Method: buildDownDependTaskLike <br>
     * @Param: [periodTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建指定任务下游依赖任务数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/25 16:35 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDownDependTaskLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, TaskAllDependDto taskAllDependDto) {
        List<PeriodTaskDef> periodTaskDefList = queryListByDependTask(periodTaskDef.getTaskCode());
        StringBuilder sb = new StringBuilder();
        if (CollectionUtil.isNotEmpty(periodTaskDefList)) {
            for (PeriodTaskDef downDependTaskDef : periodTaskDefList) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(downDependTaskDef.getTaskCode());
                buildDownNodeLike(showType, rootPeriodTaskDef, periodTaskDef, downDependTaskDef, taskAllDependDto);
            }
            log.info("构建指定任务下游依赖任务数据,downDependPeriodTaskDef:{},rootPeriodTaskDef:{},periodTaskDef:{}",sb,rootPeriodTaskDef.getTaskCode(),periodTaskDef.getTaskCode());
        }
    }

    /*
     * @Method: buildDownNodeLike <br>
     * @Param: [periodTaskDef, downDependTaskDef, taskAllDependDto] <br>
     * @Return: void <br>
     * @Description：构建指定任务下游依赖任务之间关系数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/25 16:35 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDownNodeLike(String showType, PeriodTaskDef rootPeriodTaskDef, PeriodTaskDef periodTaskDef, PeriodTaskDef downDependTaskDef, TaskAllDependDto taskAllDependDto) {
        DependRelationDto dependRelationDto = new DependRelationDto(periodTaskDef.getTaskCodeAndName(), downDependTaskDef.getTaskCodeAndName());
        if (!taskAllDependDto.getLinks().contains(dependRelationDto)) {
            log.info("构建指定任务下游依赖任务之间关系数据,downDependPeriodTaskDef:{},rootPeriodTaskDef:{},periodTaskDef:{}",downDependTaskDef.getTaskCode(),rootPeriodTaskDef.getTaskCode(),periodTaskDef.getTaskCode());
            taskAllDependDto.getLinks().add(dependRelationDto);
        }
        buildDownDependChatData(showType, rootPeriodTaskDef, downDependTaskDef, taskAllDependDto);
    }

    /*
     * @Method: downDependList <br>
     * @Param: [taskCode] <br>
     * @Return: com.hex.ds.hdrs.period.task.dto.depend.TaskAllDependListDto <br>
     * @Description：获取指定任务下游依赖任务列表<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 14:59 <br>
     * @Version： V2.0.2<br>
     */
    public TaskAllDependListDto downDependList(String taskCode) {
        PeriodTaskDef periodTaskDef = qryPeriodTaskDef(taskCode);
        Set<PeriodTaskDef> downTaskDefSet = buildDownDependList(periodTaskDef);
        downTaskDefSet.remove(periodTaskDef);
        return new TaskAllDependListDto().setPeriodTaskDefList(new ArrayList<>(downTaskDefSet));
    }

    /*
     * @Method: buildDownDependList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：查询指定任务下游依赖任务列表<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 15:00 <br>
     * @Version： V2.0.2<br>
     */
    private Set<PeriodTaskDef> buildDownDependList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> downTaskDefSet = new HashSet<>();
        downTaskDefSet.add(periodTaskDef);
        downTaskDefSet.addAll(buildDownDependTaskList(periodTaskDef));
        downTaskDefSet.addAll(buildDownDependJobList(periodTaskDef));
        return downTaskDefSet;
    }

    /*
     * @Method: buildDownDependTaskList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：获取直接依赖任务的下游依赖<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 15:00 <br>
     * @Version： V2.0.2<br>
     */
    private Set<PeriodTaskDef> buildDownDependTaskList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> downTaskDefSet = new HashSet<>();
        List<PeriodTaskDef> downDependList = queryListByDependTask(periodTaskDef.getTaskCode());
        for (PeriodTaskDef downDependTask : downDependList) {
            downTaskDefSet.addAll(buildDownDependList(downDependTask));
        }
        return downTaskDefSet;
    }

    /*
     * @Method: queryListByDependTask <br>
     * @Param: [taskCode] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.task.po.PeriodTaskDef> <br>
     * @Description：根据任务编码查询依赖该编码的任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 15:01 <br>
     * @Version： V2.0.2<br>
     */
    private List<PeriodTaskDef> queryListByDependTask(String taskCode) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("dependTask", taskCode);
        return periodTaskDefDao.qryTaskDefList(paramMap);
    }

    /*
     * @Method: buildDownDependJobList <br>
     * @Param: [periodTaskDef] <br>
     * @Return: Set<PeriodTaskDef> <br>
     * @Description：若指定任务为作业最后一个结束任务则查询依赖所属作业的下游任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 15:04 <br>
     * @Version： V2.0.2<br>
     */
    private Set<PeriodTaskDef> buildDownDependJobList(PeriodTaskDef periodTaskDef) {
        Set<PeriodTaskDef> downTaskDefSet = new HashSet<>();
        List<PeriodTaskDef> crunJobTaskList = getTaskDefsByJobCode(periodTaskDef.getJobCode());
        List<String> sortTaskCodes = sortByDependTask(crunJobTaskList);
        if (sortTaskCodes.indexOf(periodTaskDef.getTaskCode()) == (crunJobTaskList.size() - 1)) {
            List<PeriodTaskDef> downDependList = queryListByDependJob(periodTaskDef.getJobCode());
            for (PeriodTaskDef dependTaskDef : downDependList) {
                downTaskDefSet.addAll(buildDownDependList(dependTaskDef));
            }
        }
        return downTaskDefSet;
    }

    /*
     * @Method: queryListByDependJob <br>
     * @Param: [jobCode] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.task.po.PeriodTaskDef> <br>
     * @Description：根据指定作业编码查询下游依赖任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/24 15:05 <br>
     * @Version： V2.0.2<br>
     */
    private List<PeriodTaskDef> queryListByDependJob(String jobCode) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("dependJob", jobCode);
        return periodTaskDefDao.qryTaskDefList(paramMap);
    }

    /*
     * @Method: sortByDependTask <br>
     * @Param: [periodTaskDefs] <br>
     * @Return: java.util.List<java.lang.String> <br>
     * @Description：根据任务依赖进行排序<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/21 13:49 <br>
     * @Version： V2.0.2<br>
     */
    public List<String> sortByDependTask(List<PeriodTaskDef> periodTaskDefs) {
        List<String> periodTaskCodeList = periodTaskDefs.stream().map(PeriodTaskDef::getTaskCode).collect(Collectors.toList());
        // 将ArrayList转换为Map,key为id,value为pid和该对象本身组成的List
        Map<String, List<PeriodTaskDef>> periodTaskMap = buildPeriodTaskMap(periodTaskDefs, periodTaskCodeList);
        // 根据pid的依赖进行拓扑排序
        Stack<PeriodTaskDef> stack = stacekSort(periodTaskMap, periodTaskCodeList);
        // 输出排序后的结果
        List<String> sortList = new ArrayList<>();
        while (!stack.isEmpty()) {
            sortList.add(0, stack.pop().getTaskCode());
        }
        return sortList;
    }

    private Map<String, List<PeriodTaskDef>> buildPeriodTaskMap(List<PeriodTaskDef> periodTaskDefs, List<String> periodTaskCodeList) {
        Map<String, List<PeriodTaskDef>> objectMap = new HashMap<>();
        for (PeriodTaskDef periodTaskDef : periodTaskDefs) {
            List<String> dependTaskCodeList = ListUtils.intersection(Arrays.asList(StrUtil.split(periodTaskDef.getDependTask(), ",")), periodTaskCodeList);
            List<PeriodTaskDef> tempList = new ArrayList<>();
            tempList.add(periodTaskDef);
            for (String dependTaskCode : dependTaskCodeList) {
                tempList.addAll(objectMap.getOrDefault(dependTaskCode, new ArrayList<>()));
            }
            objectMap.put(periodTaskDef.getTaskCode(), tempList);
        }
        return objectMap;
    }

    private Stack<PeriodTaskDef> stacekSort(Map<String, List<PeriodTaskDef>> periodTaskMap, List<String> periodTaskCodeList) {
        Stack<PeriodTaskDef> stack = new Stack<>();
        Map<String, Boolean> visited = new HashMap<>();
        for (String taskCode : periodTaskMap.keySet()) {
            if (!visited.containsKey(taskCode)) {
                dfs(taskCode, periodTaskMap, visited, stack, periodTaskCodeList);
            }
        }
        return stack;
    }

    private void dfs(String id, Map<String, List<PeriodTaskDef>> objectMap, Map<String,
            Boolean> visited, Stack<PeriodTaskDef> stack, List<String> periodTaskCodeList) {
        if (visited.containsKey(id)) {
            return;
        } else {
            visited.put(id, true);
            List<String> dependTaskCodeList = org.apache.commons.collections4.ListUtils.intersection(Arrays.asList(StrUtil.split(objectMap.get(id).get(0).getDependTask(), ",")), periodTaskCodeList);
            for (String childId : dependTaskCodeList) {
                dfs(childId, objectMap, visited, stack, periodTaskCodeList);
            }
            stack.push(objectMap.get(id).get(0));
        }
    }
}